package com.vmj.heap;

import com.vmj.classfile.entity.attribute.ExceptionTableEntry;

/**
 * Created by yangshoujun on 2017/9/23 上午11:15.
 */
public class ExceptionHandler {

    // 异常处理范围
    int startPc;
    int endPc;
    int handlerPc;
    ClassRef catchType;

    public static ExceptionHandler[] getExceptionHandlers(ExceptionTableEntry[] entries, RuntimeConstantPool cp) {
        ExceptionHandler[] handlers = new ExceptionHandler[entries.length];
        for(int i = 0; i < handlers.length;i++) {
            ExceptionHandler handler = new ExceptionHandler();
            ExceptionTableEntry entry = entries[i];
            handler.setStartPc(entry.getStartPc());
            handler.setEndPc(entry.getEndPc());
            handler.setHandlerPc(entry.getHandlerPc());
            handler.setCatchType(getCatchType(entry.getCatchType(), cp));
            handlers[i] = handler;
        }

        return handlers;
    }

    public static ExceptionHandler findExceptionHandler(VMClass exClass, int pc, ExceptionHandler[] handlers) {
        if(handlers == null) {
            return null;
        }
        for(ExceptionHandler handler : handlers) {
            if(pc >= handler.getStartPc() && pc <= handler.getEndPc()) {
                if(handler.getCatchType() == null) {
                    return handler;
                }

                VMClass catchClass = handler.getCatchType().resolvedClass();
                if(catchClass == exClass || catchClass.isSuperClassOf(exClass)) {
                    return handler;
                }
            }
        }

        return null;
    }

    private static ClassRef getCatchType(int catchType, RuntimeConstantPool cp) {
        if(catchType == 0) {
            return null;
        }
        java.lang.Object value = cp.getConstant(catchType).getValue();
        return (ClassRef) value;
    }

    public int getStartPc() {
        return startPc;
    }

    public int getEndPc() {
        return endPc;
    }

    public int getHandlerPc() {
        return handlerPc;
    }

    public ClassRef getCatchType() {
        return catchType;
    }

    public void setStartPc(int startPc) {
        this.startPc = startPc;
    }

    public void setEndPc(int endPc) {
        this.endPc = endPc;
    }

    public void setHandlerPc(int handlerPc) {
        this.handlerPc = handlerPc;
    }

    public void setCatchType(ClassRef catchType) {
        this.catchType = catchType;
    }
}
